package com.hardson.toolkit.util;

import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Locale;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.ImageOutputStream;
import javax.swing.ImageIcon;

import org.apache.commons.io.IOUtils;

public class ImageUtil {

	public static byte[] resizePicture(final byte[] data, final int width, final int height,
			final RenderingHints hints) throws IOException {

		ByteArrayOutputStream out = new ByteArrayOutputStream(data.length);
		BufferedImage bi = ImageIO.read(IOUtils.buffer(new ByteArrayInputStream(data)));
		double Ratio = 0.0;
		// 缩放比例
		int biH = bi.getHeight();
		int biW = bi.getWidth();
		if ((biH > height) || (biW > width)) {
			Ratio = (biH > biW) ? Double.valueOf(height) / biH : Double.valueOf(width) / biW;

			Image itemp = bi.getScaledInstance(width, height, Image.SCALE_SMOOTH);

			AffineTransform atForm = AffineTransform.getScaleInstance(Ratio, Ratio);
			AffineTransformOp op = new AffineTransformOp(atForm, hints);
			itemp = op.filter(bi, null);
			ImageIO.write((BufferedImage) itemp, "jpg", out);
		}
		return out.toByteArray();

	}

	public static byte[] resizePicture(final byte[] data, final int width, final int height)
			throws IOException {
		return resizePicture(data, width, height, null);
	}

	/**
	 * 对图片进行旋转
	 *
	 * @param src   被旋转图片
	 * @param angel 旋转角度
	 * @return 旋转后的图片
	 */
	public static BufferedImage rotate(final Image src, final int angel) {
		int src_width = src.getWidth(null);
		int src_height = src.getHeight(null);
		// 计算旋转后图片的尺寸
		Rectangle rect_des = calcRotatedSize(new Rectangle(new Dimension(src_width, src_height)), angel);
		BufferedImage res = new BufferedImage(rect_des.width, rect_des.height, BufferedImage.TYPE_INT_RGB);
		Graphics2D g2 = res.createGraphics();
		// 进行转换
		g2.translate((rect_des.width - src_width) / 2, (rect_des.height - src_height) / 2);
		g2.rotate(Math.toRadians(angel), src_width / 2, src_height / 2);

		g2.drawImage(src, null, null);
		return res;
	}

	/**
	 * 计算旋转后的图片
	 *
	 * @param src   被旋转的图片
	 * @param angel 旋转角度
	 * @return 旋转后的图片
	 */
	public static Rectangle calcRotatedSize(final Rectangle src, int angel) {
		// 如果旋转的角度大于90度做相应的转换
		if (angel >= 90) {
			if (angel / 90 % 2 == 1) {
				int temp = src.height;
				src.height = src.width;
				src.width = temp;
			}
			angel = angel % 90;
		}

		double r = Math.sqrt(src.height * src.height + src.width * src.width) / 2;
		double len = 2 * Math.sin(Math.toRadians(angel) / 2) * r;
		double angelAlpha = (Math.PI - Math.toRadians(angel)) / 2;
		double angelDaltaWidth = Math.atan((double) src.height / src.width);
		double angel_dalta_height = Math.atan((double) src.width / src.height);

		int lenDaltaWidth = (int) (len * Math.cos(Math.PI - angelAlpha - angelDaltaWidth));
		int lenDaltaHeight = (int) (len * Math.cos(Math.PI - angelAlpha - angel_dalta_height));
		int desWidth = src.width + lenDaltaWidth * 2;
		int desHeight = src.height + lenDaltaHeight * 2;
		return new Rectangle(new Dimension(desWidth, desHeight));
	}

	/**
	 * 从类路径读取图片，并按长宽缩放
	 *
	 * @param fileName
	 * @param width
	 * @param height
	 * @return
	 */
	public static Image readCPImage(String fileName, final int width, final int height) {
		URL url = ImageUtil.class.getResource(fileName);
		if (url == null) {
			return null;
		}
		// File file = new File(url.getFile());
		// 注意：读取jar包里的文件，必须使用URL方式
		return readImage(url, width, height);
	}

	/**
	 * 根据文件名从类路径读取图片，并按缩放率缩放
	 *
	 * @param fileName
	 * @param zoomRate
	 * @return
	 */
	public static Image readCPImage(String fileName, float zoomRate) {
		URL url = ImageUtil.class.getResource(fileName);
		if (url == null) {
			return null;
		}
		// File file = new File(url.getFile());
		// 注意：读取jar包里的文件，必须使用URL方式
		return readImage(url, zoomRate);
	}

	/**
	 * 根据相对路径读取图片，并按长宽缩放
	 *
	 * @param relativePath
	 * @param width
	 * @param height
	 * @return
	 */
	public static Image readImage(final String relativePath, final int width, final int height) {
		String fullPath = FileUtils.getFullPath(relativePath);
		return readImage(new File(fullPath), width, height);
	}

	/**
	 * 读取一个图片文件并按长宽缩放
	 * 长宽必须同时大于0
	 *
	 * @param file
	 * @param width
	 * @param height
	 * @return
	 */
	public static Image readImage(final File file, final int width, final int height) {
		try {
			Image img = ImageIO.read(file);
			if (img != null && width > 0 && height > 0) {
				img = img.getScaledInstance(width, height, Image.SCALE_SMOOTH);
			}
			return img;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 读取一个图片文件，按缩放率计算长宽进行缩放。
	 *
	 * @param file
	 * @param zoomRate
	 * @return
	 */
	public static Image readImage(final File file, float zoomRate) {
		try {
			Image img = ImageIO.read(file);
			if (img == null) {
				return null;
			}
			int width = (int) (img.getWidth(null) * zoomRate);
			int height = (int) (img.getHeight(null) * zoomRate);
			img = img.getScaledInstance(width, height, Image.SCALE_SMOOTH);
			return img;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 读取一个图片文件并按长宽缩放
	 * 长宽必须同时大于0
	 *
	 * @param url    文件url地址，支持指向jar包里路径
	 * @param width
	 * @param height
	 * @return
	 */
	public static Image readImage(final URL url, final int width, final int height) {
		try {
			Image img = ImageIO.read(url);
			if (img != null && width > 0 && height > 0) {
				img = img.getScaledInstance(width, height, Image.SCALE_SMOOTH);
			}
			return img;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 读取一个图片文件，按缩放率计算长宽进行缩放。
	 *
	 * @param url      文件url地址，支持指向jar包里路径
	 * @param zoomRate
	 * @return
	 */
	public static Image readImage(final URL url, float zoomRate) {
		try {
			Image img = ImageIO.read(url);
			if (img == null) {
				return null;
			}
			int width = (int) (img.getWidth(null) * zoomRate);
			int height = (int) (img.getHeight(null) * zoomRate);
			img = img.getScaledInstance(width, height, Image.SCALE_SMOOTH);
			return img;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 根据相对路径，从类路径读取图片，并按长宽缩放返回图标对象
	 *
	 * @param relativePath
	 * @param width
	 * @param height
	 * @return
	 */
	public static ImageIcon readCPImageIcon(final String relativePath, final int width, final int height) {
		Image img = readCPImage(relativePath, width, height);
		return (img != null) ? new ImageIcon(img) : null;
	}

	/**
	 * 根据相对路径从类路径读取图片，并按缩放率缩放长、宽返回图标对象
	 *
	 * @param relativePath
	 * @param zoomRate
	 * @return
	 */
	public static ImageIcon readCPImageIcon(final String relativePath, float zoomRate) {
		Image img = readCPImage(relativePath, zoomRate);
		return (img != null) ? new ImageIcon(img) : null;
	}

	/**
	 * 根据相对路径读取图片文件，并按长宽缩放，返回图标对象
	 *
	 * @param relativePath
	 * @param width
	 * @param height
	 * @return
	 */
	public static ImageIcon readImageIcon(final String relativePath, final int width, final int height) {
		Image img = readImage(relativePath, width, height);
		return (img != null) ? new ImageIcon(img) : null;
	}

	/**
	 * 读取图片文件，并按长宽缩放，返回图标对象
	 *
	 * @param file
	 * @param width
	 * @param height
	 * @return
	 */
	public static ImageIcon readImageIcon(final File file, final int width, final int height) {
		Image img = readImage(file, width, height);
		return (img != null) ? new ImageIcon(img) : null;
	}

	/**
	 * jpeg图像压缩
	 *
	 * @param image
	 * @param quality
	 * @return byte[]
	 * @throws IOException
	 */
	public static byte[] jpegCompress(byte[] jpegData, float quality) throws IOException {
		BufferedImage bi = ImageIO.read(IOUtils.buffer(new ByteArrayInputStream(jpegData)));
		return jpegCompress(bi, quality);
	}

	/**
	 * jpeg图像压缩
	 *
	 * @param image
	 * @param quality
	 * @return byte[]
	 * @throws IOException
	 */
	public static byte[] jpegCompress(BufferedImage image, float quality) throws IOException {
		ByteArrayOutputStream outStream = new ByteArrayOutputStream();

		ImageWriter imgWriter = ImageIO.getImageWritersByFormatName("jpg").next();
		try (ImageOutputStream ioStream = ImageIO.createImageOutputStream(outStream);) {
			imgWriter.setOutput(ioStream);

			JPEGImageWriteParam jpegParams = new JPEGImageWriteParam(Locale.getDefault());
			jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
			jpegParams.setCompressionQuality(quality);

			imgWriter.write(null, new IIOImage(image, null, null), jpegParams);
		} finally {
			imgWriter.dispose();
		}
		return outStream.toByteArray();
	}

}
